﻿/*

  The contents of this file are subject to the Mozilla Public License Version
  1.1 (the "License"); you may not use this file except in compliance with
  the License. You may obtain a copy of the License at 
  
           http://www.mozilla.org/MPL/ 
  
  Software distributed under the License is distributed on an "AS IS" basis,
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  for the specific language governing rights and limitations under the License. 
  
  The Original Code is LunAS Library.
  
  The Initial Developer of the Original Code is
  ALCARAZ Marc (aka eKameleon)  <ekameleon@gmail.com>.
  Portions created by the Initial Developer are Copyright (C) 2004-2012
  the Initial Developer. All Rights Reserved.
  
  Contributor(s) :
  
  Alternatively, the contents of this file may be used under the terms of
  either the GNU General Public License Version 2 or later (the "GPL"), or
  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  in which case the provisions of the GPL or the LGPL are applicable instead
  of those above. If you wish to allow use of your version of this file only
  under the terms of either the GPL or the LGPL, and not to allow others to
  use your version of this file under the terms of the MPL, indicate your
  decision by deleting the provisions above and replace them with the notice
  and other provisions required by the LGPL or the GPL. If you do not delete
  the provisions above, a recipient may use your version of this file under
  the terms of any one of the MPL, the GPL or the LGPL.
  
*/
package lunas.components.textinputs 
{
    import graphics.IFillStyle;
    import graphics.ILineStyle;
    import graphics.geom.EdgeMetrics;
    
    import lunas.CoreBuilder;
    
    import system.hack;
    
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.events.Event;
    import flash.events.FocusEvent;
    import flash.events.KeyboardEvent;
    import flash.events.SoftKeyboardEvent;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    import flash.text.StageText;
    import flash.text.StageTextInitOptions;
    import flash.text.StyleSheet;
    import flash.text.engine.FontPosture;
    import flash.text.engine.FontWeight;
    
    use namespace hack ;
    
    /**
     * The builders of the NativeTextInput component.
     */
    public class NativeTextInputBuilder extends CoreBuilder
    {
        /**
         * Creates a new NativeTextInputBuilder instance.
         * @param target the target of the component reference to build.
         */
        public function NativeTextInputBuilder( target:NativeTextInput = null )
        {
            super( target );
        }
        
        /**
         * Clear the view of the component.
         */
        public override function clear():void
        {
            if( _target )
            {
                _target.removeEventListener( Event.ADDED_TO_STAGE , addedToStage , false ) ;
                _target.removeEventListener( Event.REMOVED_FROM_STAGE , removedFromStage , false ) ;
            }
            
            _freezed = false ;
            
            disposeStageText() ;
            disposeSnapshot() ;
        }
        
        /**
         * Freeze the component. 
         * @return true if the stageText can is freezed.
         */
        public function freeze():Boolean
        {
            disposeSnapshot() ;
            
            if( _stageText && _drawable )
            {
                var comp:NativeTextInput = _target as NativeTextInput ;
                if (comp )
                {
                    var style:NativeTextInputStyle = comp.style as NativeTextInputStyle ;
                    if( style )
                    {
                        var area:Rectangle = _stageText.viewPort ;
                        
                        var bitmap:BitmapData = new BitmapData( area.width, area.height , true , 0x00000000 );
                        
                        _stageText.drawViewPortToBitmapData( bitmap );
                        
                        _snapshot = new Bitmap( bitmap ) ;
                        
                        _snapshot.x = style.padding.left ;
                        _snapshot.y = style.padding.top ;
                        
                        _target.addChild( _snapshot );
                        
                        _freezed = true ;
                        
                        _stageText.visible = false;
                        
                        return true ;
                    }
                }
            }
            
            return false ;
        }
        
        /**
         * Runs the build of the component.
         */
        public override function run( ...arguments:Array ):void
        {
            if( _target )
            {
                _target.addEventListener( Event.ADDED_TO_STAGE , addedToStage , false , 0 , true ) ;
            }
        }
        
        /**
         * Unfreeze the component. 
         * @return true if the stageText is unfreezed.
         */
        public function unfreeze():Boolean
        {
            _freezed = false ;
            if( _snapshot )
            {
                if( _stageText && _target.stage )
                {
                    _stageText.visible = true ;
                }
                disposeSnapshot() ;
                return true ;
            }
            return false ;
        }
        
        /**
         * Update the view of the component.
         */
        public override function update():void
        {
            (_target as NativeTextInput).invalidateDraw() ;
            updateBackground() ;
            updateStageText() ;
            updateLayout() ;
        }
        
        ///////////
        
        /**
         * Indicates if the stage text is drawable.
         */
        hack var _drawable:Boolean ;
        
        /**
         * Indicates if the stage text is freezed.
         */
        hack var _freezed:Boolean ;
        
        /**
         * The snapshot display used to show the bitmap render of the stage text. 
         */
        hack var _snapshot:Bitmap ;
        
        /**
         * The stage text reference.
         */
        hack var _stageText:StageText ;
        
        ///////////
        
        /**
         * Invoked when the display is added to the stage.
         */
        protected function addedToStage( e:Event = null ):void
        {
            if( _target )
            {
                _target.removeEventListener( Event.ADDED_TO_STAGE , addedToStage , false ) ;
                _target.addEventListener( Event.REMOVED_FROM_STAGE , removedFromStage , false , 0 , true ) ;
            }
            
            if ( _stageText )
            {
                if( !_freezed )
                {
                    unregisterStageText() ;
                    _stageText.stage   = _target.stage ;
                    _stageText.visible = true ;
                    registerStageText() ;
                }
            }
            
            updateLayout() ;
        }
        
        /**
         * Dispatch an event with the target reference. 
         */
        protected function completeStageText( e:Event ):void
        {
            _drawable = true ;
        }
        
        /**
         * Dispatch an event with the target reference. 
         */
        protected function dispatchEvent( e:Event ):void
        {
            if( _target )
            {
                _target.dispatchEvent( e ) ;
            }
        }
        
        /**
         * Dispose the snapshot reference.
         */
        protected function disposeSnapshot():void
        {
            if( _snapshot )
            {
                if( _target.contains(_snapshot) )
                {
                    _target.removeChild( _snapshot ) ;
                }
                if( _snapshot.bitmapData )
                {
                    _snapshot.bitmapData.dispose() ;
                    _snapshot.bitmapData = null ;
                }
                _snapshot = null ;
            }
        }
        
        /**
         * Dispose the stage text reference.
         */
        protected function disposeStageText():void
        {
            _drawable = false ;
            if( _stageText )
            {
                unregisterStageText() ;
                _stageText.stage = null ;
                _stageText.dispose() ;
                _stageText = null ;
            }
        }
        
        /**
         * Registers the current stage text reference.
         */
        protected function registerStageText():void
        {
            if( _stageText )
            {
                _stageText.addEventListener( Event.COMPLETE         , completeStageText , false , 9999 , true ) ;
                _stageText.addEventListener( Event.CHANGE           , dispatchEvent , false , 9999 , true ) ;
                _stageText.addEventListener( FocusEvent.FOCUS_IN    , dispatchEvent , false , 9999 , true ) ;
                _stageText.addEventListener( FocusEvent.FOCUS_OUT   , dispatchEvent , false , 9999 , true ) ;
                _stageText.addEventListener( KeyboardEvent.KEY_DOWN , dispatchEvent , false , 9999 , true ) ;
                _stageText.addEventListener( KeyboardEvent.KEY_UP   , dispatchEvent , false , 9999 , true ) ;
                _stageText.addEventListener( SoftKeyboardEvent.SOFT_KEYBOARD_ACTIVATE   , dispatchEvent , false , 9999 , true ) ;
                _stageText.addEventListener( SoftKeyboardEvent.SOFT_KEYBOARD_ACTIVATING , dispatchEvent , false , 9999 , true ) ;
                _stageText.addEventListener( SoftKeyboardEvent.SOFT_KEYBOARD_DEACTIVATE , dispatchEvent , false , 9999 , true ) ;
            }
        }
        
        /**
         * Invoked when the display is removed from the stage
         */
        protected function removedFromStage( e:Event = null ):void
        {
            if( _target )
            {
                _target.addEventListener( Event.ADDED_TO_STAGE , addedToStage , false , 0 , true ) ;
                _target.removeEventListener( Event.REMOVED_FROM_STAGE , removedFromStage , false ) ;
            }
            if ( _stageText )
            {
                unregisterStageText() ;
                _stageText.visible = false ;
            }
            
            updateLayout() ;
        }
        
        /**
         * Registers the current stage text reference.
         */
        protected function unregisterStageText():void
        {
            if( _stageText )
            {
                _stageText.removeEventListener( Event.CHANGE           , dispatchEvent ) ;
                _stageText.removeEventListener( FocusEvent.FOCUS_IN    , dispatchEvent ) ;
                _stageText.removeEventListener( FocusEvent.FOCUS_OUT   , dispatchEvent ) ;
                _stageText.removeEventListener( KeyboardEvent.KEY_DOWN , dispatchEvent ) ;
                _stageText.removeEventListener( KeyboardEvent.KEY_UP   , dispatchEvent ) ;
                _stageText.removeEventListener( SoftKeyboardEvent.SOFT_KEYBOARD_ACTIVATE   , dispatchEvent ) ;
                _stageText.removeEventListener( SoftKeyboardEvent.SOFT_KEYBOARD_ACTIVATING , dispatchEvent ) ;
                _stageText.removeEventListener( SoftKeyboardEvent.SOFT_KEYBOARD_DEACTIVATE , dispatchEvent ) ;
            }
        }
        
        /**
         * Update the background.
         */
        protected function updateBackground( theme:IFillStyle = null , border:ILineStyle = null ):void
        {
            var comp:NativeTextInput = _target as NativeTextInput ;
            if (comp )
            {
                var style:NativeTextInputStyle = comp.style as NativeTextInputStyle ;
                if( style )
                {
                    comp.lock() ;
                    
                    comp._align = style.align ;
                    comp.fill   = theme  ? theme  : ( comp._enabled ? style.theme       : style.themeDisabled ) ;
                    comp.line   = border ? border : ( comp._enabled ? style.themeBorder : style.themeBorderDisabled ) ;
                    
                    comp.unlock() ;
                }
                
                comp.draw() ;
            }
        }
        
        /**
         * Update the elements.
         */
        hack function updateLayout():void
        {
            var comp:NativeTextInput = _target as NativeTextInput ;
            if ( comp )
            {
                var style:NativeTextInputStyle = comp.style as NativeTextInputStyle ;
                if( style )
                {
                    if( _stageText )
                    {
                        var padding:EdgeMetrics = style._padding ;
                        
                        var area:Rectangle = comp.fixArea().clone() ;
                        
                        area.x      += padding.left ;
                        area.y      += padding.top ;
                        area.width  -= padding.horizontal ;
                        area.height -= padding.vertical ;
                        
                        area.width  = Math.max( 0 , area.width ) ;
                        area.height = Math.max( 0 , area.height ) ;
                        
                        var pos:Point = new Point( area.x, area.y );
                        
                        pos = comp.localToGlobal( pos ) ;
                        
                        area.x = pos.x ;
                        area.y = pos.y ;
                        
                        _drawable = false ;
                        
                        _stageText.viewPort = area ;
                    }
                }
            }
        }
        
        /**
         * Update the stage text.
         */
        protected function updateStageText():void
        {
            var comp:NativeTextInput = _target as NativeTextInput ;
            if (comp )
            {
                var style:NativeTextInputStyle = comp.style as NativeTextInputStyle ;
                if( style )
                {
                    if( _stageText == null || (_stageText.multiline != style.multiline )  )
                    {
                        if( _stageText )
                        {
                            comp._text = _stageText.text ;
                            disposeStageText() ;
                        }
                        
                        _stageText      = new StageText( new StageTextInitOptions( style.multiline ) ) ;
                        _stageText.text = comp._text || "" ;
                        
                        if( comp.stage )
                        {
                            _stageText.stage   = comp.stage ;
                            _stageText.visible = true ;
                            registerStageText() ;
                        }
                        else
                        {
                            _stageText.visible = false ;
                        }
                    }
                    
                    _stageText.autoCapitalize    = style.autoCapitalize ;
                    _stageText.autoCorrect       = style.autoCorrect ;
                    _stageText.color             = style.color ;
                    _stageText.displayAsPassword = style.displayAsPassword ;
                    _stageText.editable          = style.editable && comp._enabled ;
                    _stageText.fontFamily        = style.fontFamily ;
                    _stageText.fontPosture       = style.fontPosture ;
                    _stageText.fontSize          = style.fontSize ;
                    _stageText.fontWeight        = style.fontWeight ;
                    _stageText.locale            = style.locale ;
                    _stageText.maxChars          = style.maxChars ;
                    _stageText.restrict          = style.restrict ;
                    _stageText.returnKeyLabel    = style.returnKeyLabel ;
                    _stageText.softKeyboardType  = style.softKeyboardType ;
                    _stageText.textAlign         = style.textAlign ;
                    
                    updateStyleSheet() ;
                }
            }
        }
        
        /**
         * Refreshs the field with the optional styleSheet.
         */
        protected function updateStyleSheet():void
        {
            if( !_stageText )
            {
                return ;
            }
            
            var comp:NativeTextInput = _target as NativeTextInput ;
            if ( comp )
            {
                var style:NativeTextInputStyle = comp.style as NativeTextInputStyle ;
                if( style )
                {
                    var styleSheet:StyleSheet = style.styleSheet ;
                    if( styleSheet )
                    {
                        var css:Object = styleSheet.getStyle( "." + style.styleName ) ;
                        if( css )
                        {
                            // color
                            
                            if( "color" in css )
                            {
                                _stageText.color = Number( String(css.color).replace("#" , "0x") ) ;
                            }
                            
                            // font-family
                            
                            if( "fontFamily" in css )
                            {
                                _stageText.fontFamily = css.fontFamily ;
                            }
                            
                            // font-family
                            
                            if( "fontFamily" in css )
                            {
                                _stageText.fontFamily = css.fontFamily ;
                            }
                            
                            // font-size
                            
                            if( "fontSize" in css )
                            {
                                _stageText.fontSize = parseInt(css.fontSize) ;
                            }
                            
                            // font-style
                            
                            if( "fontStyle" in css )
                            {
                                _stageText.fontPosture = (css.fontStyle == FontPosture.ITALIC) ? FontPosture.ITALIC : FontPosture.NORMAL ;
                            }
                            
                            // font-style
                            
                            if( "fontWeight" in css )
                            {
                                _stageText.fontWeight = (css.fontWeight == FontWeight.BOLD) ? FontWeight.BOLD : FontWeight.NORMAL ;
                            }
                        }
                    }
                }
            }
        }
    }
}
